/**
 * This class represents the UI for setting the user attributes.
 */
package org.hackystat.ui.sensordatabrowser.client;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * This class represents the UI for setting the user attributes.
 * @author David J. Nickles
 *
 */
public class UserPanels extends VerticalPanel implements FocusListener, ClickListener, 
  WindowResizeListener { 

  private Boolean userStatus;
  private Button registerUserButton;
  private CalendarPanels calendarPanels;
  private Date cookieExpires;
  private Image userPanelImage;
  private Label userLabel;
  private Label passwordLabel;
  private Label userPanelFeedback;
  private PasswordTextBox passwordTextBox;
  private Session session;
  private TextBox userTextBox;
  
  /**
   * This method creates a new settings panel.
   * 
   * @param session the current session attributes
   */
  public UserPanels(Session session) {
    this.session = session;
    this.userStatus = Boolean.FALSE;
    this.cookieExpires = new Date((new Date()).getTime() + Session.COOKIESPAN);
    
    HorizontalPanel row1 = new HorizontalPanel();
    this.userPanelImage = new Image(Images.USER_IMAGE);
    this.userPanelImage.setStyleName(Styles.STATUSIMAGESTYLE);
    row1.add(this.userPanelImage);
    VerticalPanel row1col2 = new VerticalPanel();
    Label userPanelTitle = new Label("User");
    row1col2.add(userPanelTitle);
    this.userPanelFeedback = new Label("Enter the user credentials.");
    this.userPanelFeedback.setStyleName(Styles.EXAMPLELABELSTYLE);
    row1col2.add(this.userPanelFeedback);
    row1.add(row1col2);
    RootPanel.get("userStatusSlot").add(row1);

    VerticalPanel row2n3 = new VerticalPanel();
    row2n3.setStyleName(Styles.SETTINGSPANELPANESTYLE);
    HorizontalPanel row2 = new HorizontalPanel();
    Label userLabel = new Label("Username:");
    userLabel.setStyleName(Styles.SMALLLABELSTYLE);
    row2.add(userLabel);
    this.userTextBox = new TextBox();
    String userCookie = Cookies.getCookie("user");
    if (userCookie == null) {
      this.userTextBox.setText("");
      Cookies.setCookie("user", this.userTextBox.getText(), this.cookieExpires);
      this.session.setUser(this.userTextBox.getText());
    }
    else {
      this.userTextBox.setText(userCookie);
      this.session.setUser(this.userTextBox.getText());
    }
    this.userTextBox.addFocusListener(this);
    row2.add(this.userTextBox);
    HorizontalPanel row25 = new HorizontalPanel();
    this.userLabel = new Label("Example: user@hackystat.org");
    this.userLabel.setStyleName(Styles.EXAMPLELABELSTYLE);
    row25.add(this.userLabel);
    row25.add(this.registerUserButton = new Button("Register"));
    //this.registerUserButton.setStyleName(Styles.BUTTONSTYLE);
    this.registerUserButton.addClickListener(this);
    row2n3.add(row2);
    row2n3.add(row25);
    HorizontalPanel row3 = new HorizontalPanel();
    Label keyLabel = new Label("Password:");
    row3.add(keyLabel);
    this.passwordTextBox = new PasswordTextBox();
    String passwordCookie = Cookies.getCookie("password");
    if (passwordCookie == null) {
      this.passwordTextBox.setText("");
      Cookies.setCookie("password", this.passwordTextBox.getText(), this.cookieExpires);
      this.session.setPassword(this.passwordTextBox.getText());
    }
    else {
      this.passwordTextBox.setText(passwordCookie);
      this.session.setPassword(this.passwordTextBox.getText());
    }
    this.passwordTextBox.addFocusListener(this);
    row3.add(this.passwordTextBox);
    keyLabel.setStyleName(Styles.SMALLLABELSTYLE);
    this.passwordLabel = new Label("Example: YEr7zqHKA7eg");
    this.passwordLabel.setStyleName(Styles.EXAMPLELABELSTYLE);
    row2n3.add(row3);
    row2n3.add(this.passwordLabel);
    RootPanel.get("userSettingsSlot").add(row2n3);
    
    Window.addWindowResizeListener(this);
    this.setWidth(Integer.toString(Window.getClientWidth() - 34) + Styles.PIXELSUFFIX);
    
    if (this.userTextBox.getText().length() > 0 && this.passwordTextBox.getText().length() > 0) {
      this.rpcIsRegistered();
    }
  }
  
  /**
   * Nothing happens when the settings fields are given focus.
   * @param sender the UI widget that was given focus
   */
  public void onFocus(Widget sender) {
    /* nothing to do here */
  }
  
  /**
   * This method gets the user name that was entered into the UI.
   * @return the user name.
   */
  public String getUser() {
    return this.userTextBox.getText();
  }
  
  /**
   * This method gets the password that was entered into the UI.
   * @return the password.
   */
  public String getPassword() {
    return this.passwordTextBox.getText();
  }
  
  /**
   * This method sets the correct panel Images from the host and user status.
   */
  private void displayStatus() {
    if (this.userStatus.booleanValue()) {
      this.userPanelImage.setUrl(Images.USER_VALID);
      this.userPanelFeedback.setText("User " + this.userTextBox.getText() + " authorized.");
      this.userPanelFeedback.setStyleName(Styles.VALIDLABELSTYLE);
      this.calendarPanels = new CalendarPanels(this.session);
    } 
    else {
      this.userPanelImage.setUrl(Images.USER_INVALID);
      this.userPanelFeedback.setText("User " + this.userTextBox.getText() 
        + " authorization failed.");
      this.userPanelFeedback.setStyleName(Styles.INVALIDLABELSTYLE);
    }
  }
  
  /**
   * This method sets the state of the user & key validation.
   * @param state Boolean represents the state of the user valid=true, invalid=false
   */
  private void setUserStatus(Boolean state) {
    if (state.booleanValue()) {
      this.userStatus = Boolean.TRUE;
      Cookies.setCookie("user", this.userTextBox.getText(), this.cookieExpires);
      session.setUser(this.userTextBox.getText());
      Cookies.setCookie("password", this.passwordTextBox.getText(), this.cookieExpires);
      session.setPassword(this.passwordTextBox.getText());
      rpcGetProjectParcels();
      //displayStatus();
    } 
    else {
      this.userStatus = Boolean.FALSE;
      session.setUser(null);
      session.setPassword(null);
      displayStatus();
    }
  }
  
  /**
   * Check with the servlet to see if the user/password is valid.
   */
  private void rpcIsRegistered() {
    this.userPanelImage.setUrl(Images.WAIT_IMAGE);
    RPCServiceFactory.getInstance().getService().isRegistered(this.session.getSensorbaseHost(), 
      this.userTextBox.getText(), this.passwordTextBox.getText(), new AsyncCallback()
      {
        public void onSuccess(Object result) {
          setUserStatus((Boolean) result);
        }

        public void onFailure(Throwable caught) {
          if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
            log(RPCServiceFactory.PRCERRORNAME, "Cannot invoke user validation on servlet.");
          } 
          else {
            log(RPCServiceFactory.PRCERRORNAME, caught.toString());
          }
        }
      });
  }  
  
  /**
   * This method sets the state of the host uri validation.
   * @param state Boolean represents the state of the user valid=true, invalid=false
   */
  public void setRegisterUserStatus(Boolean state) {
    this.userPanelImage.setUrl(Images.USER_IMAGE);
    if (state.booleanValue()) {
      this.userPanelFeedback.setText("Registration requested for " + this.userTextBox.getText() 
        + ". Please check your e-mail for the response.");
      this.userPanelFeedback.setStyleName(Styles.VALIDLABELSTYLE);
    }
    else {
      this.userPanelFeedback.setText("Unable to request registration for " 
          + this.userTextBox.getText());
      this.userPanelFeedback.setStyleName(Styles.INVALIDLABELSTYLE);
    }
  }
  
  /**
   * Check with the servlet to see if the user/password is valid.
   */
  private void rpcRegisterUser() {
    this.userPanelImage.setUrl(Images.WAIT_IMAGE);
    RPCServiceFactory.getInstance().getService().registerUser(this.session.getSensorbaseHost(), 
      this.userTextBox.getText(), new AsyncCallback()
      {
        public void onSuccess(Object result) {
          setRegisterUserStatus((Boolean) result);
        }

        public void onFailure(Throwable caught) {
          if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
            log(RPCServiceFactory.PRCERRORNAME, "Cannot invoke user validation on servlet.");
          } 
          else {
            log(RPCServiceFactory.PRCERRORNAME, caught.toString());
          }
        }
      });
  }  
  
  /**
   * This method sets the state of the user & key validation.
   * @param projects the list of projects for this user.
   * 
   * @gwt.typeArgs projects <java.util.ArrayList<java.lang.String>>
   */
  private void setUserProjects(ArrayList projects) {
    this.session.setProjects(projects);
    displayStatus();
  }
  
  /**
   * Check with the servlet to see if the user/password is valid.
   */
  private void rpcGetProjectParcels() {
    this.userPanelImage.setUrl(Images.WAIT_IMAGE);
    RPCServiceFactory.getInstance().getService().getProjectParcels(
      this.session.getSensorbaseHost(), this.userTextBox.getText(),
      this.passwordTextBox.getText(), new AsyncCallback()
      {
        public void onSuccess(Object result) {
          setUserProjects((ArrayList) result);
        }

        public void onFailure(Throwable caught) {
          if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
            session.log(RPCServiceFactory.PRCERRORNAME, 
              "Cannot invoke user validation on servlet.");
          } 
          else {
            session.log(RPCServiceFactory.PRCERRORNAME, caught.toString());
          }
        }
      });
  }  

  /** 
   * When any of the settings fields lose focus then check to see if the information is valid.
   * @param sender the UI widget that is losing focus.
   */
  public void onLostFocus(Widget sender) {
    if ((sender.equals(this.userTextBox)) || (sender.equals(this.passwordTextBox))) {
      this.session.setUser(this.userTextBox.getText());
      this.session.setPassword(this.passwordTextBox.getText());
      rpcIsRegistered();
    }
  }
  
  /**
   * Check if user is valid.
   * @return true if the credentials have been validated with the server. 
   */
  public Boolean userValid() {
    return this.userStatus;
  }
  
  /**
   * Log this message in the display.
   * @param header the message header or subject
   * @param body the message body
   */
  private void log(String header, String body) {
    Window.alert(header + " : " + body);
  }

  /** 
   * Listens for clicks on the UI elements.
   * @param sender the UI widget that is losing focus.
   */
  public void onClick(Widget sender) {
    if (sender.equals(this.registerUserButton)) {
      rpcRegisterUser();
    }
  }

  /** 
   * Listens for user resizing of the window.
   * @param width of the adjusted window..
   * @param height of the adjusted window.
   */
  public void onWindowResized(int width, int height) {
    this.setWidth(Integer.toString(width - 34) + Styles.PIXELSUFFIX);
  }
}
